package com.tbit.uqbike.client.service.impl;

import com.tbit.uqbike.center.pojo.MachineStatus;
import com.tbit.uqbike.client.constant.MapConstant;
import com.tbit.uqbike.client.constant.SysConstant;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.pojo.newEntity.Forbidden;
import com.tbit.uqbike.client.service.CalibrateService;
import com.tbit.uqbike.client.util.GeoUtil;
import com.tbit.uqbike.client.util.calibrate.GpsCorrect;
import com.tbit.uqbike.client.util.calibrate.GpsReverseCorrect;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

@Service("calibrateService")
public class CalibrateServiceImpl implements CalibrateService {
    /**
     * 经纬度格式化
     */
    private DecimalFormat df = new DecimalFormat("#.#########");

    public static void main(String[] args) {
        CalibrateServiceImpl calibrateService = new CalibrateServiceImpl();
		/*Point p = new Point();
		//113.86961,23.11034
		p.setX(115.3831);
		p.setY(25.13842);
		p= calibrateService.calibrate(p,SysConstant.BAIDU);
		System.out.println(p);*/

        Point point = calibrateService.googleToOrigial(new Point(115.38869596947318, 25.135427114106157));
        System.out.println(point);
		/*machineLat: 25.135427114106157
		machineLon: 115.38869596947318
		machineNO: "003523767"
		orderNO: "202008130086475698"
		phoneLat: 25.13548629613061
		phoneLon: 115.38863792535415
		phoneTime: 1597254061000
		userCode: "003523767"*/
    }

    @Override
    public void calibrateOffSet(TerPosition terPosition, int mapType) {
        double lng = terPosition.getLon();
        double lat = terPosition.getLat();

        Point p = calibrateOffSet(lng, lat, mapType);
        terPosition.setLonC(Double.parseDouble(df.format(p.getX())));
        terPosition.setLatC(Double.parseDouble(df.format(p.getY())));
    }

    @Override
    public void calibrateOffSet(List<TerPosition> terPositions, int mapType) {
        for (int i = 0; i < terPositions.size(); i++) {
            TerPosition terPosition = terPositions.get(i);
            double lng = terPosition.getLon();
            double lat = terPosition.getLat();

            Point p = calibrateOffSet(lng, lat, mapType);
            terPosition.setLonC(Double.parseDouble(df.format(p.getX())));
            terPosition.setLatC(Double.parseDouble(df.format(p.getY())));
        }

    }

    /**
     * 获取校准点
     */
    public Point calibrateOffSet(double lo, double la, int mapType) {
        Point point = new Point(lo, la);
        if (MapConstant.MAP_BAIDU == mapType) {
            double[] latlng = GpsCorrect.oriToBaidu(la, lo);
            point.setX(latlng[1]);
            point.setY(latlng[0]);
        } else if (MapConstant.MAP_GOOGLE == mapType) {
            double[] latlng = GpsCorrect.oriToGoogle(la, lo);
            point.setX(latlng[1]);
            point.setY(latlng[0]);
        }

        return point;
    }

    /**
     * 获取逆向校准点
     */
    public Point calibrateRecerseOffSet(double lo, double la, int mapType) {
        Point point = new Point(lo, la);
        if (MapConstant.MAP_BAIDU == mapType) {
            double[] latlng = GpsReverseCorrect.baiduToOri(la, lo);
            point.setX(latlng[1]);
            point.setY(latlng[0]);
        } else if (MapConstant.MAP_GOOGLE == mapType) {
            double[] latlng = GpsReverseCorrect.googleToOri(la, lo);
            point.setX(latlng[1]);
            point.setY(latlng[0]);
        }

        return point;
    }

    @Override
    public void celibrateParkPoint(List<ParkPoint> parkPoints, int mapType) {
        for (int i = 0; i < parkPoints.size(); i++) {
            ParkPoint parkPoint = parkPoints.get(i);
            double lng = parkPoint.getLo();
            double lat = parkPoint.getLa();

            Point p = calibrateOffSet(lng, lat, mapType);
            parkPoint.setLoC(Double.parseDouble(df.format(p.getX())));
            parkPoint.setLaC(Double.parseDouble(df.format(p.getY())));
        }
    }

    @Override
    public void celibrateParkPoint(ParkPoint parkPoint, int mapType) {
        double lng = parkPoint.getLo();
        double lat = parkPoint.getLa();

        Point p = calibrateOffSet(lng, lat, mapType);
        parkPoint.setLoC(Double.parseDouble(df.format(p.getX())));
        parkPoint.setLaC(Double.parseDouble(df.format(p.getY())));
    }

    /**
     * 经纬度校准
     */
    public Point calibrate(Point point, Integer mapType) {
        Point cP = calibrateOffSet(point.getX(), point.getY(), mapType);
        return new Point(Double.parseDouble(df.format(cP.getX())), Double.parseDouble(df.format(cP.getY())));
    }

    /**
     * 百度坐标转原始坐标
     */
    public Point baiduToOrigial(Point point) {
        Point bP = calibrateRecerseOffSet(point.getX(), point.getY(), SysConstant.BAIDU);
        return new Point(Double.parseDouble(df.format(bP.getX())), Double.parseDouble(df.format(bP.getY())));
    }

    /**
     * 谷歌坐标转原始坐标
     */
    public Point googleToOrigial(Point point) {
        Point bP = calibrateRecerseOffSet(point.getX(), point.getY(), SysConstant.GOOGLE);
        return new Point(Double.parseDouble(df.format(bP.getX())), Double.parseDouble(df.format(bP.getY())));
    }

    @Override
    /**经纬度转换（原始坐标、百度坐标、谷歌坐标之间相互转换）*/
    public Point calibrate(Point point, Integer from, Integer to) {
        if (from == SysConstant.ORIGINAL && to == SysConstant.BAIDU) {
            /*原始到百度*/
            point = calibrate(point, SysConstant.BAIDU);
        } else if (from == SysConstant.ORIGINAL && to == SysConstant.GOOGLE) {
            /*原始到谷歌*/
            point = calibrate(point, SysConstant.GOOGLE);
        } else if (from == SysConstant.BAIDU && to == SysConstant.ORIGINAL) {
            /*百度到原始*/
            point = baiduToOrigial(point);
        } else if (from == SysConstant.GOOGLE && to == SysConstant.ORIGINAL) {
            /*谷歌到原始*/
            point = googleToOrigial(point);
        }
        return point;
    }

    @Override
    public void calGeo(Geo geo, Integer oriMapType, Integer targetMapType) {
        List<Point> points = GeoUtil.getPoints(geo.getPoints());

        if (geo.getPointsC() == null) {
            List<Point> pointCs = new ArrayList<Point>();
            for (Point point : points) {
                pointCs.add(calibrate(point, oriMapType, targetMapType));
            }
            geo.setPoints(GeoUtil.getPointToString(pointCs));
        } else {
            geo.setPoints(geo.getPointsC());
        }
    }

    @Override
    public void calibrateOffSet(MachineStatus machineStatus, int mapType) {
        double lng = machineStatus.getLon();
        double lat = machineStatus.getLat();

        Point p = calibrateOffSet(lng, lat, mapType);
        machineStatus.setLonC(Double.parseDouble(df.format(p.getX())));
        machineStatus.setLatC(Double.parseDouble(df.format(p.getY())));
    }

    @Override
    public void calParkPoint(ParkPoint parkPoint, Integer oriMapType, Integer targetMapType) {
        /**多边形的经纬度直接使用数据库保存的原始经纬度和谷歌校准经纬度*/

        /*校准经纬度为原始经纬度*/
        Point point = new Point(parkPoint.getLo(), parkPoint.getLa());
        point = calibrate(point, oriMapType, targetMapType);
        if (point != null) {
            parkPoint.setLoC(point.getX());
            parkPoint.setLaC(point.getY());
        }
    }

    @Override
    public void calForbidden(Forbidden forbidden, Integer oriMapType, Integer targetMapType) {
        Point pointDB = new Point(forbidden.getCenterLo(), forbidden.getCenterLa());
        pointDB = calibrate(pointDB, oriMapType, targetMapType);
        if (pointDB != null) {
            forbidden.setCenterLo(pointDB.getX());
            forbidden.setCenterLa(pointDB.getY());
        }
        List<Point> points = GeoUtil.getPoints(forbidden.getPoints());

        if (forbidden.getPointsC() == null) {
            List<Point> pointCs = new ArrayList<Point>();
            for (Point point : points) {
                pointCs.add(calibrate(point, oriMapType, targetMapType));
            }
            forbidden.setPoints(GeoUtil.getPointToString(pointCs));
        } else {
            forbidden.setPoints(forbidden.getPointsC());
        }
    }

    @Override
    public void celibrateProhibit(List<ProhibitArea> prohibitAreas, int mapType) {
        for (int i = 0; i < prohibitAreas.size(); i++) {
            ProhibitArea prohibitArea = prohibitAreas.get(i);
            double lng = prohibitArea.getLo();
            double lat = prohibitArea.getLa();

            Point p = calibrateOffSet(lng, lat, mapType);
            prohibitArea.setLoC(Double.parseDouble(df.format(p.getX())));
            prohibitArea.setLaC(Double.parseDouble(df.format(p.getY())));
            List<Point> points = GeoUtil.getPoints(prohibitArea.getPoints());
            if (prohibitArea.getPointsC() == null) {
                List<Point> pointCs = new ArrayList<Point>();
                for (Point point : points) {
                    pointCs.add(commonCalibrate(point, MapConstant.MAP_ORI, mapType));
                }
                prohibitArea.setPointsC(GeoUtil.getPointToString(pointCs));
            }

        }
    }

    @Override
    public Point commonCalibrate(Point point, Integer from, Integer to) {
        if (from == SysConstant.ORIGINAL && to == SysConstant.BAIDU) {
            /*原始到百度*/
            point = calibrate(point, SysConstant.BAIDU);
        } else if (from == SysConstant.ORIGINAL && to == SysConstant.GOOGLE) {
            /*原始到谷歌*/
            point = calibrate(point, SysConstant.GOOGLE);
        } else if (from == SysConstant.BAIDU && to == SysConstant.ORIGINAL) {
            /*百度到原始*/
            point = baiduToOrigial(point);
        } else if (from == SysConstant.GOOGLE && to == SysConstant.ORIGINAL) {
            /*谷歌到原始*/
            point = googleToOrigial(point);
        }
        return point;
    }

    @Override
    public String calVert(String points, Integer from, Integer to) {
        List<Point> pointList = GeoUtil.getPoints(points);
        List<Point> pointCs = new ArrayList<Point>();
        for (Point point : pointList) {
            pointCs.add(commonCalibrate(point, from, to));
        }
        return GeoUtil.getPointToString(pointCs);
    }
}  